<?php

namespace app\bll;

use app\controller\uc\Logreg;
use core\attribute\Template;
use core\lib\schema\Table;
use Exception;
use hulang\tool\StrHelper;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Query\Builder;
use support\Db;

class  User
{


    /**
     * 查找信息
     *
     * @param integer $id
     * @return array
     */
    public function find(int $id): array
    {
        $data =  Db::table('frame_user')
            ->where('id', '=', $id)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    #[Template]
    /**
     * 查询信息【不包含密码】
     *
     * @param integer $id
     * @return array
     */
    public function findWithoutPassword(int $id): array
    {
        $data =  Db::table('frame_user')
            ->where('id', '=', $id)
            ->first();
        if ($data !== null) {
            $data =  get_object_vars($data);
            unset($data['pwd']);
            return $data;
        }
        return [];
    }

    /**
     * 添加用户 用户注册
     *
     * @param array $data
     * @return integer
     */
    public function register(array $data): int
    {
        //获取field
        $bllUserField = new UserField;
        $fields = $bllUserField->selRegisterField();
        foreach ($fields as $field) {
            if ($field['require'] == 1 && trim($data[$field['name']]) == '') {
                throw new Exception($field['title'] . '必填');
            }
            if ($field['require'] == 1 && $field['reg'] != '') {
                if (!preg_match($field['reg'], $data[$field['name']])) {
                    throw new Exception($field['title'] . '格式不正确');
                }
            }

            //判断唯一
            if ($field['unique'] == 1 && isset($data[$field['name']]) != '') {
                if ($this->fieldValExit($field['name'], $data[$field['name']])) {
                    throw new Exception($field['title'] . '已存在');
                }
            }
        }
        $data['pwd']          = password_hash($data['pwd'], PASSWORD_DEFAULT);
        $data['registertime'] = time();
        return Db::table('frame_user')
            ->insertGetId($data);
    }


    /**
     * 判断某个字段值是否存在 验证重复性
     *
     * @param string $field
     * @param string $val
     * @return boolean
     */
    public function fieldValExit(string $field, string $val): bool
    {
        return Db::table('frame_user')
            ->where($field, '=', $val)
            ->exists();
    }

    /**
     * 根据用户名查询
     *
     * @param string $username
     * @return array
     */
    public function findByUsername(string $username): array
    {
        $data =  Db::table('frame_user')
            ->where('username', '=', $username)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }


    /**
     * 根据手机号查询
     *
     * @param string $phone
     * @return array
     */
    public function findByPhone(string $phone): array
    {
        $data =  Db::table('frame_user')
            ->where('phone', '=', $phone)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    /**
     * 账户登录
     *
     * @param string $username
     * @param string $pwd
     * @return array
     */
    public function accountLogin(string $username, string $pwd): array
    {
        if (!$info = $this->findByUsername($username)) {
            throw new Exception('账号不正确');
        }

        if (!password_verify($pwd, $info['pwd'])) {

            throw new Exception('密码不正确');
        }

        if ($info['status'] != 1) {
            throw new Exception('账号已被禁用');
        }

        return $info;
    }

    /**
     * 手机登录
     *
     * @param string $phone
     * @return array
     */
    public function phoneLogin(string $phone): array
    {
        if (!$info = $this->findByPhone($phone)) {
            throw new Exception('手机号不正确');
        }
        if ($info['status'] != 1) {
            throw new Exception('账号已被禁用');
        }
        return $info;
    }

    /**
     * 获取积分
     *
     * @param integer $uid
     * @param integer $integral
     * @param integer $addsub 1 增加 2 扣除
     * @param integer $ruleid 规则id 可为0
     * @param string $remark 描述
     * @return void
     */
    public function obtainIntegral(
        int $uid,
        int $integral,
        int $addsub = 1,
        int $ruleid = 0,
        string $remark = ''
    ) {

        Db::beginTransaction();
        try {

            //设置积分
            $userinfo = $this->find($uid);
            if (!$userinfo) {
                throw new Exception('用户不存在');
            }

            $realIntegral = 0;
            if ($addsub == 1) {
                $realIntegral = $userinfo['integral'] + $integral;
            }
            if ($addsub == 2) {
                $realIntegral =  $userinfo['integral'] - $integral;
            }

            $realIntegral = $realIntegral < 0 ? 0 : $realIntegral;
            Db::table('frame_user')->where('id', '=', $uid)
                ->update([
                    'integral' => $realIntegral
                ]);


            //设置记录
            Db::table('frame_user_integral_log')
                ->insert(
                    [
                        'uid'      => $uid,
                        'ruleid'   => $ruleid,
                        'remark'   => $remark,
                        'addsub'   => $addsub,
                        'integral' => $integral,
                        'addtime'  => time(),
                    ]
                );

            Db::commit();
        } catch (Exception $ex) {
            throw $ex;
            Db::rollBack();
        }
    }


    /**
     * 通过积分规则更新用户积分
     *
     * @param integer $uid
     * @param integer $integral
     * @param integer $addsub 1 增加 2 扣除
     * @param array $rule
     * @return void
     */
    public function obtainIntegralByRule(
        int $uid,
        array $rule

    ) {
        Db::beginTransaction();
        try {
            //设置积分
            $userinfo = $this->find($uid);
            if (!$userinfo) {
                throw new Exception('用户不存在');
            }


            $realIntegral = 0;
            $canobtain = true; //是否可以获得

            if ($rule['addsub'] == 1) {

                /* 判断是否超过当日积分或整体积分 */
                $realIntegral = $userinfo['integral'] + $rule['integral'];
                $bllUserIntegralLog = new UserIntegralLog();
                if ($rule['daylimit'] != 0) {
                    $daylimit = $bllUserIntegralLog->userTodayIntegral($uid, $rule['id']);
                    if ($daylimit + $rule['integral'] > $rule['daylimit']) {
                        $canobtain = false;
                    }
                }

                if ($rule['alllimit'] != 0) {
                    $alllimit = $bllUserIntegralLog->userIntegral($uid, $rule['id']);
                    if ($alllimit + $rule['integral'] > $rule['alllimit']) {
                        $canobtain = false;
                    }
                }
            }
            if ($rule['addsub'] == 2) {
                $realIntegral =  $userinfo['integral'] - $rule['integral'];
            }

            if ($canobtain) {
                $realIntegral = $realIntegral < 0 ? 0 : $realIntegral;

                Db::table('frame_user')->where('id', '=', $uid)
                    ->update([
                        'integral' => $realIntegral
                    ]);


                //设置记录
                Db::table('frame_user_integral_log')
                    ->insert(
                        [
                            'uid'      => $uid,
                            'ruleid'   => $rule['id'],
                            'remark'   => $rule['title'],
                            'addsub'   => $rule['addsub'],
                            'integral' => $rule['integral'],
                            'addtime'  => time(),
                        ]
                    );
            }


            Db::commit();
        } catch (Exception $ex) {
            Db::rollBack();
            throw $ex;
        }
    }



    /**
     * 获取用户其他信息
     *
     * @param string|array $table 表信息 or表名
     * @param integer $uid 用户uid
     * @return array
     */
    #[Template]
    public function userInfomation(string|array $table, int $uid): array
    {
        if (is_string($table)) {
            $bllUserTable = new UserTable();
            $table = $bllUserTable->findByName($table);
        }

        if ($table['multiline'] == 1) //多行记录
        {
            return Db::table($table['name'])
                ->where('uid', '=', $uid)
                ->get()
                ->map(function ($value) {
                    return (array)$value;
                })
                ->toArray();
        } else {
            $data = Db::table($table['name'])
                ->where('uid', '=', $uid)
                ->first();
            return $data === null ? [] : get_object_vars($data);
        }
    }

    /**
     * 获取用户的一条信息
     *
     * @param string $tablename
     * @param integer $id
     * @param integer $uid
     * @return array
     */
    public function findInfomationByUid(
        string $tablename,
        int $id,
        int $uid
    ): array {
        $data = Db::table($tablename)
            ->where('uid', '=', $uid)
            ->where('id', '=', $id)
            ->first();
        return $data === null ? [] : get_object_vars($data);
    }

    /**
     * 添加一条信息
     *
     * @param integer $uid
     * @param array $data
     * @param string $tablename
     * @return integer
     */
    public function addUserInfomation(array $data, string $tablename): int
    {
        try {

            $bllUserField = new UserField();
            $fields       = $bllUserField->select($tablename);
            $data         = $this->formatPostFieldData($fields, $data);
            $data         = $this->filterNoExitField($tablename, $data);
            $this->verifyField($fields, $data);

            return Db::table($tablename)
                ->insertGetId($data);
        } catch (Exception $ex) {
            throw $ex;
        }
    }

    /**
     * 编辑信息
     *
     * @param integer $uid
     * @param array $data
     * @param string $tablename
     * @param integer|null $id
     * @return integer
     */
    public function editUserInfomation(
        int $uid,
        array $data,
        string $tablename,
        ?int $id = null,
    ): int {
        try {

            $bllUserTable = new UserTable();
            $tableinfo    = $bllUserTable->findByName($tablename);

            $bllUserField = new UserField();
            $fields       = $bllUserField->select($tablename);
            $data         = $this->formatPostFieldData($fields, $data);
            $data         = $this->filterNoExitField($tablename, $data);
            $this->verifyField($fields, $data);

            if ($tableinfo['multiline'] == 1) {
                return Db::table($tablename)
                    ->where('id', '=', $id)
                    ->where('uid', '=', $uid)
                    ->update($data);
            } else {
                $infoexit =  Db::table($tablename)->where('uid', '=', $uid)
                    ->first();
                if (!$infoexit) {
                    $data['uid'] = $uid;
                    return Db::table($tablename)
                        ->insertGetId($data);
                } else {
                    return Db::table($tablename)
                        ->where('uid', '=', $uid)
                        ->update($data);
                }
            }
        } catch (Exception $ex) {
            throw $ex;
        }
    }

    /**
     * 删除信息
     *
     * @param integer $uid
     * @param string $tablename
     * @param integer|null $id
     * @return integer
     */
    public function delUserInfomation(
        int $id,
        int $uid,
        string $tablename
    ): int {
        return Db::table($tablename)
            ->where('id', '=', $id)
            ->where('uid', '=', $uid)
            ->delete();
    }

    /**
     * 排除不存在的字段【自定义信息表】
     *
     * @param string $tablename
     * @param array $data
     * @return array
     */
    private function filterNoExitField(string $tablename, array $data): array
    {
        $table = new Table($tablename);
        $cloumns = $table->getColumns();
        $cloumns = array_column($cloumns, null, 'name');
        foreach ($data as $key => $d) {

            if (!isset($cloumns[$key])) {
                unset($data[$key]);
            }
        }
        return $data;
    }

    /**
     * 格式化字段数据【自定义信息表】
     *
     * @param array $fields
     * @param array $data
     * @return array
     */
    private function formatPostFieldData(array $fields, array $data): array
    {

        foreach ($fields as $key => $field) {
            if (isset($data[$field['name']]) && is_array($data[$field['name']])) {
                $data[$field['name']] = json_encode($data[$field['name']], JSON_UNESCAPED_UNICODE);
            }
            /* if (isset($data[$field['name']]) && $field['editor'] == 1) {
                $data[$field['name']] = htmlspecialchars_decode($data[$field['name']]);
            }*/
        }

        return $data;
    }

    /**
     * 验证字段【自定义信息表】
     *
     * @param array $fields
     * @param array $data
     * @return void
     */
    private function verifyField(array $fields, array $data)
    {
        foreach ($fields as $field) {
            if (
                isset($data[$field['name']])
                && $field['require'] == 1
                && !trim($data[$field['name']])
            ) {
                throw new Exception($field['title'] . '必填');
            }

            if (
                isset($data[$field['name']]) &&
                trim(
                    $data[$field['name']]
                ) && $field['reg'] != ''
            ) {
                if (!preg_match($field['reg'], $data[$field['name']])) {
                    throw new Exception($field['title'] . '格式不正确');
                }
            }
        }
    }


    /**
     * 修改密码
     *
     * @param string $oldpwd
     * @param string $newpwd
     * @param string $renewpwd
     * @param integer $uid
     * @return void
     */
    public function changePwd(
        string $oldpwd,
        string $newpwd,
        string $renewpwd,
        int $uid
    ) {

        $userinfo =  $this->find($uid);
        if (!$userinfo) {
            throw new Exception('用户不存在');
        }

        if (!password_verify($oldpwd, $userinfo['pwd'])) {
            throw new Exception('旧密码不正确');
        }

        if ($newpwd != $renewpwd) {
            throw new Exception('确认密码不正确');
        }

        return Db::table('frame_user')
            ->where('id', '=', $uid)
            ->update([
                'pwd' => password_hash($newpwd, PASSWORD_DEFAULT)
            ]);
    }


    /**
     * 设置用户状态
     *
     * @param integer $uid
     * @param integer $status
     * @return integer
     */
    public function setStatus(int $uid, int $status): int
    {
        return Db::table('frame_user')
            ->where('id', '=', $uid)
            ->update([
                'status' => $status
            ]);
    }

    /**
     * 重置某用户密码
     *
     * @param integer $id
     * @param string $pwd
     * @return integer
     */
    public function resetPwd(int $uid, string $pwd): int
    {
        return Db::table('frame_user')
            ->where('id', '=', $uid)
            ->update([
                'pwd' => password_hash($pwd, PASSWORD_DEFAULT)
            ]);
    }


    /**
     * 根据手机重置密码
     *
     * @param string $username
     * @param string $phone
     * @return string 新密码
     */
    public function resetPwdByPhone(string $username, string $phone): string
    {
        $userinfo = $this->findByUsername($username);
        if (!$userinfo) {
            throw new Exception('用户不存在');
        }

        if ($userinfo['phone'] != $phone) {
            throw new Exception('手机号不正确');
        }

        $newpwd = StrHelper::Random(8);
        $this->resetPwd($userinfo['id'], $newpwd);

        return $newpwd;
    }

    /**
     * 根据邮箱重置密码
     *
     * @param string $username
     * @param string $email
     * @return string
     */
    public function resetPwdByEmail(string $username, string $email): string
    {
        $userinfo = $this->findByUsername($username);
        if (!$userinfo) {
            throw new Exception('用户不存在');
        }

        if ($userinfo['email'] != $email) {
            throw new Exception('邮箱不正确');
        }

        $newpwd = StrHelper::Random(8);
        $this->resetPwd($userinfo['id'], $newpwd);

        return $newpwd;
    }

    /**
     * 分页查询
     *
     * @param string $name
     * @param string $ident
     * @param integer $pagesize
     * @return LengthAwarePaginator
     */
    public function paginator(
        string $username = '',
        string $phone = '',
        string $email = '',
        string $name = '',
        string $organcompanyid = '',
        int $pagesize = 20
    ): LengthAwarePaginator {
        $items =  Db::table('frame_user')
            ->leftJoin('frame_user_basicinfo', 'frame_user.id', '=', 'frame_user_basicinfo.uid')
            ->when($username != '', function (Builder  $query) use ($username) {
                return $query->where('frame_user.username', 'like', '%' . $username . '%');
            })
            ->when($phone != '', function (Builder  $query) use ($phone) {
                return $query->where('frame_user.phone', 'like', '%' . $phone . '%');
            })
            ->when($email != '', function (Builder  $query) use ($email) {
                return $query->where('frame_user.email', 'like', '%' . $email . '%');
            })
            ->when($name != '', function (Builder  $query) use ($name) {
                return $query->where('frame_user_basicinfo.name', 'like', '%' . $name . '%');
            })
            ->when($organcompanyid != '', function (Builder  $query) use ($organcompanyid) {
                return $query->where('frame_user_basicinfo.organcompanyid', '=', $organcompanyid);
            })

            ->orderBy('id', 'desc')
            ->paginate(
                perPage: $pagesize,
                columns: [
                    'frame_user.*',
                    'frame_user_basicinfo.name',
                    'frame_user_basicinfo.organcompanyid',
                    'frame_user_basicinfo.organpostid',
                    'frame_user_basicinfo.sex'
                ]
            );

        // 获取所有岗位
        $bllOrgPost = new OrganPost();
        $posts      = $bllOrgPost->select();
        $posts      = array_column($posts, null, 'id');

        // 公司
        $bllOrganCompany = new OrganCompany();
        $companyTree = $bllOrganCompany->tree();
        foreach ($items as $key => $item) {
            if (isset($posts[$item->organpostid])) {
                $items[$key]->organpostname = $posts[$item->organpostid]['title'];
            } else {
                $items[$key]->organpostname = '';
            }

            $companynames = '';
            if ($item->organcompanyid) {
                $parentcompanys =  $bllOrganCompany->getAncestorsAndSelf($item->organcompanyid,  $companyTree);

                foreach ($parentcompanys as $parentcompany) {
                    $companynames .= $parentcompany['title'] . ' ';
                }
            }
            $items[$key]->organcompanyname = $companynames;
        }
        return $items;
    }
}
